﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Diagnostics;
using ALDIOrganizer.Properties;

namespace ALDIOrganizer
{
    // A super-class which represents all rotas in the CurrentFile, as well as the _staff    
    public partial class DataFile
    {
        public BindingList<Rota> RotasDataSource
        {
            get
            {
                var result = new BindingList<Rota>();
                foreach (Rota rota in rotas.Values)
                {
                    result.Add(rota);
                }
                return result;
            }
        }

        public BindingList<Rota> RotasExcludingPastDataSource
        {
            get
            {
                var result = new BindingList<Rota>();
                
                foreach (var freshRota in
                                        (from rota in rotas.Values
                                         where rota.Sunday >= DateTime.Now
                                         select rota))
                {
                    result.Add(freshRota);
                }

                return result;
            }
        }

        public IList<KeyValuePair<string, DateTime>> WeeksDataSource
        {
            get
            {
                var result = new List<KeyValuePair<string, DateTime>>();
                var sameYear = !OverOneYear;
                foreach (var rota in rotas)
                {
                    if (rota.Value.ProperAction == RotaAction.None)
                    {
                        continue;
                    }
                    var week = rota.Key.WeekOfYear();
                    string displayName;
                    if (sameYear)
                    {
                        displayName = Resources.FORM_MAINFORM_cbWeek.Replace(
                            "#",
                            week.ToString());
                    }
                    else
                    {
                        displayName = Resources.FORM_MAINFORM_cbWeek_Year.Replace(
                            "#",                        
                            week.ToString()).Replace(
                            "$",
                            (rota.Key.Year % 100).ToString());
                    }
                    result.Add(new KeyValuePair<string,DateTime>(
                        displayName,
                        rota.Key));
                }
                return result;
            }
        }

        private Rota Get(Rota pRefillRota, bool pPrevious)
        {
            var difference = pPrevious ? -7 : 7;
            var date = pRefillRota.Monday.AddDays(difference);
            return rotas.Keys.Contains(date) ? rotas[date] : null;
        }

        internal Rota GetPreviousCopy(Rota pRefillRota)
        {
            return Get(pRefillRota, true).DeepCopy();
        }

        internal Rota GetNextCopy(Rota pRota)
        {
            return Get(pRota, false).DeepCopy();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param Name="pMonday"></param>
        /// <returns></returns>
        public Rota GetRotaCopy(DateTime pMonday)
        {
            return rotas.Keys.Contains(pMonday) ? rotas[pMonday].DeepCopy() : null;
        }


        internal Rota GetNeighbouringRota(
            Rota pRota,
            RelativePosition pRelativePosition)
        {
            if (_rotas == null)
            {
                return null;
            }
            var monday = (pRota != null) ? pRota.Monday : DateTime.Today;
            if (pRelativePosition == RelativePosition.Next)
            {
                monday = monday.AddDays(7);
            }
            if (pRelativePosition == RelativePosition.Previous)
            {
                monday = monday.AddDays(-7);
            }
            return rotas.Keys.Contains(monday) ? rotas[monday] : null;
        }

        internal bool IsPreviousExistingAndAccessible(Rota pRota)
        {
            var previous = GetNeighbouringRota(pRota, RelativePosition.Previous);
            return previous != null &&
                previous.ProperAction != RotaAction.None;
        }

        internal bool IsNextExistingAndAccessible(Rota pRota)
        {
            var next = GetNeighbouringRota(pRota, RelativePosition.Next);
            return next != null &&
                next.ProperAction != RotaAction.None;
        }

        public Rota CurrentRota
        {
            get
            {
                var currentMonday = DateTime.Today.MondayOfThatWeek();
                return rotas.Keys.Contains(currentMonday) ?
                    rotas[currentMonday] :
                    null;
            }
        }

        public Rota NextRota
        {
            get
            {
                return GetNeighbouringRota(
                    CurrentRota,
                    RelativePosition.Next);
            }
        }

        public KeyValuePair<bool, Int64[]> PreviousWeekClosers(Rota pForRota)
        {
            var previous = GetNeighbouringRota(
                pForRota,
                RelativePosition.Previous);
            var exists = false;
            var ids = new List<Int64>();
            if (previous != null &&
                !previous.IsEmpty)
            {
                ids = previous.SundayClosers.ToList();
                exists = true;
            }
            return new KeyValuePair<bool, long[]>(
                exists,
                ids.ToArray());
        }

        public IEnumerable<Rota> GetRotasBasedOn(string pTemplateName)
        {
            return from rota in rotas.Values
                   where rota.TemplateName == pTemplateName
                   select rota;
        }

        public void RecalculateRotasBasedOn(string pTemplateName)
        {
            var anyRecomputed = false;
            foreach (var rota in GetRotasBasedOn(pTemplateName))
            {
                rota.RecomputeTotalHoursField();
                anyRecomputed = true;
            }
            if (anyRecomputed) // to avoid raising "false alarm" in case if there weren't any rotas based on pTemplateName
            {
                Modified = true; // launches OnModified event
            }
        }

        /// <summary>
        /// Is Template of the given Name exclusively used by the given RotaPackaging?
        /// </summary>        
        /// <param Name="Name">Name of the Template</param>
        /// <param Name="pRota">RotaPackaging in question</param>
        /// <remarks>
        /// When a user modifies a Template, it is going to affect other rotas based On the same Template.
        /// User should be informed about this and given choice to come up with a new Name for the Template,
        /// creating a new, independent version of it. (Or cancel the action altogether).
        /// </remarks>
        public bool IsTemplateExclusivelyMine(string pTemplateName, Rota pRota)
        {
            var query = from rota in rotas.Values
                        where rota.TemplateName == pTemplateName // all rotas based On the same Template...
                        & !rota.IsEmpty
                        & rota.Monday != pRota.Monday     // which are NOT pRota
                        select rota;
            return !query.Any();
        }

    }
}